package naga.x.platform2.app.support;

import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;

import naga.x.platform2.app.mapper.RechargeMapper;
import naga.x.platform2.app.mapper.RechargeTemplateMapper;
import naga.x.platform2.app.model.GameServer;
import naga.x.platform2.app.model.Recharge;
import naga.x.platform2.app.model.Recharge.State;
import naga.x.platform2.app.model.RechargeTemplate;
import naga.x.platform2.utils.HttpUtils;
import naga.x.platform2.utils.IOUtils;
import naga.x.platform2.utils.LRUCache;
import naga.x.platform2.utils.PlatformUtils;
import naga.x.platform2.utils.StringUtils;

@Service
public class RechargeSupport implements InitializingBean, Runnable {

	@Autowired
	private RechargeTemplateMapper templateMapper;
	@Autowired
	private RechargeMapper mapper;
	@Autowired
	private GameServerSupport gameServers;
	
	private Map<Integer, RechargeTemplate> templatesMap;
	
	private BlockingQueue<Recharge> queue = new LinkedBlockingQueue<Recharge>();
	private boolean closed;
	private Thread thread;
	private Map<String, Recharge> ordersMap = new LRUCache<String, Recharge>(256); // 订单缓存
	
	protected static final Logger LOG = LoggerFactory.getLogger(RechargeSupport.class);
	
	public RechargeSupport() {
		Thread t = new Thread(this);
		t.setName("RECHARGE QUEUE");
		t.setDaemon(true);
		t.start();
		thread = t;
		LOG.info("[RECHARGE QUEUE]STARTED");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		List<RechargeTemplate> templates = templateMapper.findAll();
		templatesMap = new HashMap<Integer, RechargeTemplate>();
		for (RechargeTemplate template : templates) {
			templatesMap.put(template.getId(), template);
		}
	}
	
	public RechargeTemplate getTemplate(Integer id) {
		return templatesMap.get(id);
	}
	
	public Recharge find(String orderId) {
		Recharge r = ordersMap.get(orderId);
		if (r != null) {
			return r;
		}
		r = mapper.find(orderId);
		if (r != null) {
			ordersMap.put(orderId, r);
		}
		return r;
	}
	
	/**
	 * @see #offer(Recharge, State)
	 * @param r
	 * @return
	 */
	@Deprecated
	public boolean offer(Recharge r) {
		return offer(r, State.SUCC);
	}
	
	public boolean offer(Recharge r, State state) {
		Recharge dup = find(r.getOrderId());
		if (dup != null && dup.getState() == state) { // 订单重复（订单号、状态均相同视为重复），不处理
			return false;
		}
		r.setState(state);
		ordersMap.put(r.getOrderId(), r);
		
		queue.offer(r);
		LOG.info("[RECHARGE OFFER]{}", r);
		return true;
	}
	
	public void close() {
		closed = true;
		try {
			thread.join(); // 等待queue线程结束
		} catch (Exception e) {
			LOG.error("[RECHARGE QUEUE]CLOSE ERROR", e);
		}
	}

	@Override
	public void run() {
		while (!closed) {
			flushAll();
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
			}
		}
		flushAll();
		LOG.info("[RECHARGE QUEUE]CLOSED");
	}
	
	private void flushAll() {
		while (!queue.isEmpty()) {
			Recharge r = queue.poll();
			flush(r);
		}
	}
	
	private void flush(Recharge r) {
		if (r.getId() == 0) {
			mapper.save(r);
		} else {
			mapper.update(r);
		}
		
		if (r.getState() != State.SUCC) {
			LOG.info("[RECHARGE NOT NOTIFY]OBJ[{}]", r);
			return;
		}
		
		GameServer gs = gameServers.get(r.getServerId());
		if (gs == null) {
			LOG.error("[RECHARGE NOTIFY ERROR]CAUSE[GAME SERVER NOT FOUND]" + r);
			return;
		}
		byte[] b = JSON.toJSONBytes(r);
		b = Base64.getEncoder().encode(b);
		String url = gs.getPayCallbackUrl();
		Map<String, String> params = new TreeMap<String, String>();
		params.put("result", StringUtils.bytesToString(b, IOUtils.UTF8));
		params.put("sign", PlatformUtils.makeSign(gs, params));
		String s = HttpUtils.post(url, params);
		LOG.info("[RECHARGE NOTIFY]URL[{}]OBJ[{}]RES[{}]", url, r, s);
	}
	
}
